package org.yzhzc.friend.service.user.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.yzhzc.common.core.constants.Constants;
import org.yzhzc.common.core.domain.TableDataInfo;
import org.yzhzc.common.core.enums.ExamListType;
import org.yzhzc.common.core.enums.ResultCode;
import org.yzhzc.common.core.utils.ThreadLocalUtil;
import org.yzhzc.common.security.exception.ServiceException;
import org.yzhzc.common.security.service.TokenService;
import org.yzhzc.friend.domain.exam.dto.ExamQueryDTO;
import org.yzhzc.friend.domain.exam.entity.Exam;
import org.yzhzc.friend.domain.exam.vo.ExamVO;
import org.yzhzc.friend.domain.user.entity.UserExam;
import org.yzhzc.friend.manager.ExamCacheManager;
import org.yzhzc.friend.manager.UserCacheManager;
import org.yzhzc.friend.mapper.exam.ExamMapper;
import org.yzhzc.friend.mapper.user.UserExamMapper;
import org.yzhzc.friend.service.user.IUserExamService;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 用户竞赛服务实现类。
 * 提供用户参与竞赛、查询用户竞赛列表等功能。
 */
@Slf4j
@Service
public class UserExamService implements IUserExamService {

    @Autowired
    private ExamMapper examMapper; // 竞赛数据访问接口

    @Autowired
    private UserExamMapper userExamMapper; // 用户竞赛关系数据访问接口

    @Autowired
    private TokenService tokenService; // Token 服务，用于解析用户 Token

    @Autowired
    private ExamCacheManager examCacheManager; // 竞赛缓存管理器，用于管理竞赛相关缓存

    @Value("${jwt.secret}") // 从配置文件中注入 JWT 密钥
    private String secret;

    @Autowired
    private UserCacheManager userCacheManager; // 用户缓存管理器，用于管理用户相关缓存

    /**
     * 用户参与竞赛。
     *
     * @param token  用户 Token
     * @param examId 竞赛 ID
     * @return 插入的用户竞赛关系记录数
     * @throws ServiceException 如果竞赛不存在、竞赛已开始或用户已参与竞赛，则抛出异常
     */
    @Override
    public int enter(String token, Long examId) {
        // 根据竞赛 ID 查询竞赛信息
        Exam exam = examMapper.selectById(examId);
        if (exam == null) {
            throw new ServiceException(ResultCode.FAILED_NOT_EXISTS); // 竞赛不存在
        }
        if (exam.getStartTime().isBefore(LocalDateTime.now())) {
            throw new ServiceException(ResultCode.EXAM_STARTED); // 竞赛已开始
        }

        // 从线程本地变量中获取当前用户 ID
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);

        // 查询用户是否已参与该竞赛
        UserExam userExam = userExamMapper.selectOne(new LambdaQueryWrapper<UserExam>()
                .eq(UserExam::getExamId, examId)
                .eq(UserExam::getUserId, userId));
        if (userExam != null) {
            throw new ServiceException(ResultCode.USER_EXAM_HAS_ENTER); // 用户已参与竞赛
        }

        // 将用户竞赛关系添加到缓存
        examCacheManager.addUserExamCache(userId, examId);

        // 创建用户竞赛关系记录并插入数据库
        userExam = new UserExam();
        userExam.setExamId(examId);
        userExam.setUserId(userId);
        return userExamMapper.insert(userExam);
    }

    /**
     * 查询用户竞赛列表。
     * 优先从缓存中查询，如果缓存中没有数据，则从数据库中查询并同步到缓存。
     *
     * @param examQueryDTO 竞赛查询条件
     * @return 分页的竞赛列表数据
     */
    @Override
    public TableDataInfo list(ExamQueryDTO examQueryDTO) {
        // 从线程本地变量中获取当前用户 ID
        Long userId = ThreadLocalUtil.get(Constants.USER_ID, Long.class);

        // 设置查询类型为用户竞赛列表
        examQueryDTO.setType(ExamListType.USER_EXAM_LIST.getValue());

        // 从缓存中获取竞赛列表的总数
        Long total = examCacheManager.getListSize(ExamListType.USER_EXAM_LIST.getValue(), userId);
        List<ExamVO> examVOList;

        // 如果缓存中没有数据，则从数据库中查询
        if (total == null || total <= 0) {
            // 使用分页插件进行分页查询
            PageHelper.startPage(examQueryDTO.getPageNum(), examQueryDTO.getPageSize());
            examVOList = userExamMapper.selectUserExamList(userId);

            // 将数据库中的数据同步到缓存
            examCacheManager.refreshCache(ExamListType.USER_EXAM_LIST.getValue(), userId);
            total = new PageInfo<>(examVOList).getTotal();
        } else {
            // 从缓存中获取竞赛列表
            examVOList = examCacheManager.getExamVOList(examQueryDTO, userId);
            total = examCacheManager.getListSize(examQueryDTO.getType(), userId);
        }

        // 如果竞赛列表为空，则返回空数据
        if (CollectionUtil.isEmpty(examVOList)) {
            return TableDataInfo.empty();
        }

        // 返回分页的竞赛列表数据
        return TableDataInfo.success(examVOList, total);
    }
}